La notation L permet d’imposer à R de créer un nombre sous format integer, moins gourmand en mémoire (pour des raisons d’efficacité).
class(1)
[1] "numeric"
class(1L)
[1] "integer"
1.1.2 Les listes
# Créer une listeliste <-list()# Pré-allouer une liste de 3 élémentsliste <-vector(mode ="list", 3)liste
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
# Ajouter un élément à une listeliste <-list(1, 2)# Il faut passer par cette syntaxeliste <-c(liste, list(3))liste
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
# Trier une listeliste <-list("2"=2, "0"=0, "1"=1)liste
$`2`
[1] 2
$`0`
[1] 0
$`1`
[1] 1
liste[order(names(liste))]
$`0`
[1] 0
$`1`
[1] 1
$`2`
[1] 2
# Extraction de listesliste <-list(nombres =1:5, lettres = letters[1:5])liste$nombres
[1] 1 2 3 4 5
# On veut faire appel à un élement de la liste à partir d'une variable extérieurevar <-"nombres"
# Ne marche pas, car nombres est en caractèreliste$var
NULL
# Fonctionneliste[[var]]
[1] 1 2 3 4 5
# Sélection dans une listeliste <-list(nombres =1:5, lettres = letters[1:5])liste["nombres"]
$nombres
[1] 1 2 3 4 5
is.list(liste["nombres"])
[1] TRUE
liste[["nombres"]]
[1] 1 2 3 4 5
is.list(liste[["nombres"]])
[1] FALSE
# Suppression des éléments d'une listeliste <-list(nombres =1:5, lettres = letters[1:5])liste[-1]
$lettres
[1] "a" "b" "c" "d" "e"
liste["nombres"] <-NULLliste
$lettres
[1] "a" "b" "c" "d" "e"
# Dernier élément de chaque composante d'une listeliste <-list(1:26, letters)lapply(liste, tail, 1)
[[1]]
[1] 26
[[2]]
[1] "z"
1.2 Les affectations
1.2.1 Généralités
# Importance des espacesx<-3# S'agit-il de ?x <-3# Ou de ?x <-3
[1] FALSE
# Il s'agit du premier cas !x
[1] 3
# Les {} permettent de réaliser une affectation (<-) au sein d'un traitement plus complexe !# Exemple ici : sommer les positions paires multipliées par 2 et les positions impaires multipliées par 3sum({x <-1:6 ; x[1:length(x) %%2==0] <- x[1:length(x) %%2==0] *2 ; x[1:length(x) %%2!=0] <- x[1:length(x) %%2!=0] *3 ; x})
[1] 51
# Afficher ou non la valeur de l'objet affecté pendant l'affectationx <- pi(x <- pi)
[1] 3.141593
1.2.2 Le comportement de l’opérateur c()
# c() est instable : c(x, y) n'est pas forcément du même type que c(y, x)# format doublec(NA, Sys.Date())
[1] NA 20208
# format Datec(Sys.Date(), NA)
[1] "2025-04-30" NA
# Combiner des dates et date-times avec c() conduit à des résultats potentiellement incorrectsdate <-as.Date("2025-01-01")datetime <-as.POSIXct("2025-01-01 09:00")# Correctc(date, datetime)
# Autre possibilité avec switch, mais à réserver aux variables caractères !condition <-function(langue ="Français") {switch(langue, Français ="salut",Anglais ="hello",Russe ="привет",stop("salut"))}condition("Français")
[1] "salut"
1.5 Les valeurs manquantes
# Transformer les valeurs manquantes en 0x <-data.frame(X1 =c(1, NA, 2), X2 =c(NA, NA, 3))x
X1 X2
1 1 NA
2 NA NA
3 2 3
x[is.na(x)] <-0x
X1 X2
1 1 0
2 0 0
3 2 3
# Pour les valeurs manquantes, toujours utiliser is.na et non ==NA==c(3, 1, 3, NA)
[1] NA NA NA NA
is.na(c(3, 1, 3, NA))
[1] FALSE FALSE FALSE TRUE
# Utiliser %in% et non == pour vérifier une appartenance à plusieurs variablesx1 <-1:6x1 ==c(1, 5)
[1] TRUE FALSE FALSE FALSE FALSE FALSE
x1 %in%c(1, 5)
[1] TRUE FALSE FALSE FALSE TRUE FALSE
# Sélection de données en cas de valeurs manquantesxna <-c(1, NA, 3, 2, 4, 2)
# Avec ce code, les NA sont conservésxna[xna ==2]
[1] NA 2 2
# Code sans les NAxna[!is.na(xna) & xna ==2]
[1] 2 2
# Code compact sans les NAxna[which(xna ==2)]
[1] 2 2
# Incidence des NA dans le calcul de statistiques !# Besoin de l'instruction na.rm = TRUE pour en supprimer l'incidencex <-c(1, 5, 6, NA, 8)mean(x)
[1] NA
mean(x, na.rm =TRUE)
[1] 5
max(x)
[1] NA
max(x, na.rm =TRUE)
[1] 8
# Une moyenne de NA donne NaN (Not a Number) avec na.rm = TRUE !mean(c(NA, NA, NA), na.rm =TRUE)
[1] NaN
# Et donne NA avec na.rm = FALSE !mean(c(NA, NA, NA), na.rm =FALSE)
[1] NA
1.6 Sélection d’éléments
# Le 1er élément est numéroté 1 et non 0 comme dans Pythonx <-1:3x[c(0, 4)] <-c(-1, 9)# Marche !!for (i in0:3) print(x[i])
numeric(0)
[1] 1
[1] 2
[1] 3
# Cas où les noms ne sont pas uniquesx <-c(a =1, b =2, a =3)x["a"]
# Attention aux parenthèses !n <-10# Inattendu ! Correspond à (1-1, 2-1, 3-1, ..., 10-1)1:n-1
[1] 0 1 2 3 4 5 6 7 8 9
# Correct1:(n-1)
[1] 1 2 3 4 5 6 7 8 9
# Minimum ou maximum élément par élémentx1 <-c(1, 2, 5, 6, 8)x2 <-c(4, 0, 7, 2, 1)# Minimum : 2 possibilitéspmin(x1, x2)
[1] 1 0 5 2 1
mapply(min, x1, x2)
[1] 1 0 5 2 1
# Maximum : 2 possibilitéspmax(x1, x2)
[1] 4 2 7 6 8
mapply(max, x1, x2)
[1] 4 2 7 6 8
# Calculer (x - min) / (max - min) pour chaque élément x d'un vecteurx <-c(1,2,3)sapply(x, function(xi, mn, mx) {(xi - mn) / (mx - mn)}, mn =min(x), mx =max(x))
[1] 0.0 0.5 1.0
2.2 Principe de coercion
Dans les comparaisons, les objets R sont successivement convertis en logical, integer, numeric, complex et character, jusqu’à ce que la comparaison puisse se faire.
# TRUE / FALSE est transformé en integer (1 / 0)TRUE==1
[1] TRUE
TRUE==2
[1] FALSE
FALSE==0
[1] TRUE
# TRUE est convertit en characterTRUE=="1"
[1] FALSE
# 5 est convertit en character5<'7'
[1] TRUE
# 50 est convertit en character50<'7'
[1] TRUE
2.3 Principe de recycling
En R Base, quand 2 vecteurs ne sont pas de même taille, le plus court vecteur est recyclé pour être de même taille que le plus long vecteur.
# Si la taille du plus long vecteur est un entier multiple de la taile du plus court, R n'affiche pas d'avertissementx <-c(1, 2, 3)y <-c(1, 2, 3, 4, 5, 6)x + y
[1] 2 4 6 5 7 9
# Si la taille du plus long vecteur n'est pas un entier multiple de la taille du plus court, R affiche un avertissementx <-c(1, 2, 3)y <-c(1, 2, 3, 4, 5, 6, 7)x + y
Warning in x + y: longer object length is not a multiple of shorter object
length
[1] 2 4 6 5 7 9 8
# Mais certaines fonctions pratiquent le recycling sans avertissementpaste(1:3, 1:2)
[1] "1 1" "2 2" "3 1"
ifelse(1:3, 1:2, 1:2)
[1] 1 2 1
# Et data.frame() renvoie une erreur#data.frame(1:2, 1:3)
# Informations sur la session de RsessionInfo()Sys.info().Platform# Version de RR.version.stringgetRversion()# Lien vers le bureau de l'utilisateurfile.path(Sys.getenv("USERPROFILE"), "Desktop")# Chemin de l'exécutable R est-il installé ?R.home("bin")# Où sont installés les packages R.libPaths()# Version d'un package installé (ici openxlsx)# packageVersion("openxlsx")
3.3 Le pipe sur R
Cet opérateur permet d’enchaîner les opérations et d’avoir un code plus lisible.
Il existe différents types :
Le pipe de Rbase :|>
Le pipe du tidyverse :%>%
Les deux pipes fonctionnent de la même manière mais diffèrent sur les points suivants :
Le format en résultat de sapply est imprévisible :
# integersapply(1L, function(x) c(x, x))
[,1]
[1,] 1
[2,] 1
# listsapply(integer(), function(x) c(x, x))
list()
Le résultat de ifelse() dépend du format de la condition :
# logicalifelse(NA, 1L, 1L)
[1] NA
# integerifelse(FALSE, 1L, 1L)
[1] 1
La fonction if utilisée sans else renvoie NULL si la condition est FALSE. Ceci permet d’écrire de façon élégante des conditions simples. Par exemple, prendre en compte un s final à un nom seulement si la valeur est strictement supérieure à 1 :
NombreDeLignes <-function(baseDeDonnees) { ligne <-nrow(baseDeDonnees)paste0(ligne, " ligne", if (ligne >1) "s")}NombreDeLignes(mtcars)
[1] "32 lignes"
NombreDeLignes(mtcars[1,])
[1] "1 ligne"
Pré-allouer un vecteur de dimension 3 :
x <-rep(NA, 3)
3.5 List-comprehensions en R
Equivalent des list-comprehensions de Python en R !
# Equivalent des list-comprehensions de Python en R# Somme des entiers de 1 à 1 000 multiples de 3 ou 5, en une ligne !# 4 manières de fairesum({l <-1:1000 ; l[l %%3==0| l %%5==0]})
Si la mémoire vive de l’ordinateur est saturée, on peut essayer de la “purger” en utilisant la fonction gc() de R.
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 909369 48.6 1779524 95.1 1779524 95.1
Vcells 1768114 13.5 10146329 77.5 7610193 58.1
4.2 La fonction subset()
La fonction subset() présente deux intérêts par rapport à la sélection avec [ :
les lignes où la condition évaluée est NA sont retirées :
exemple_subset <-data.frame(x =c(1, 2, NA), y =c("a", "b", "c"))# Avec []exemple_subset[exemple_subset$x ==1, ]
x y
1 1 a
NA NA <NA>
# Avec subset()subset(exemple_subset, x ==1)
x y
1 1 a
l’option par défaut est drop = FALSE, ce qui garantit que la base de résultat est un dataframe :
library(tidyverse)exemple_subset <-data.frame(x =c(1, 2, NA), y =c("a", "b", "c"))# Avec []exemple_subset[exemple_subset$x ==1, "x"] %>%is.data.frame()
[1] FALSE
# Avec subset()subset(exemple_subset, x ==1, x) %>%is.data.frame()
[1] TRUE
4.3 Les fonctions try() et tryCatch()
La fonction try() permet de poursuivre le programme malgré la survenue d’une erreur. Dans l’exemple suivant, le programme affiche bien “Suite du programme” malgré l’erreur au code précédent.
try(log("x")) ; print("Suite du programme")
Error in log("x") : non-numeric argument to mathematical function
[1] "Suite du programme"
La fonction tryCatch() est plus élaborée, et permet de programmer une valeur par défaut en cas d’erreur.
La fonction renvoie un NA si la fonction log() ne peut pas être appliquée, comme c’est le cas sur l’exemple pour la valeur “a”.
FonctionLog(1)
[1] 0
FonctionLog("x")
[1] NA
4.4 Les fonctions sort(), order() et rank()
sort() trie un vecteur par ordre croissant. rank() donne le rang de chaque élément du vecteur, le plus petit élément se voyant attribué le rang 1. order() renvoie l’indice du vecteur trié par ordre croissant.
vecteur <-c(5,3,1,2,4)sort(vecteur)
[1] 1 2 3 4 5
order(vecteur)
[1] 3 4 2 5 1
rank(vecteur)
[1] 5 3 1 2 4
Une autre solution que sort() pour trier un vecteur est :
vecteur <-c(5,3,1,2,4)vecteur[order(vecteur)]
[1] 1 2 3 4 5
À noter aussi que sort() permet aussi d’exécuter simultanément les fonctions sort() et order(). Ainsi :
# Fonction sort()sort(vecteur, index.return =TRUE)$x
[1] 1 2 3 4 5
sort(vecteur)
[1] 1 2 3 4 5
# Fonction order()sort(vecteur, index.return =TRUE)$ix
[1] 3 4 2 5 1
order(vecteur)
[1] 3 4 2 5 1
4.5 Les fonctions :, seq(), seq_len() et seq_along()
# Ne pas confondre !seq(0:10)
[1] 1 2 3 4 5 6 7 8 9 10 11
0:10
[1] 0 1 2 3 4 5 6 7 8 9 10
seq(0, 10)
[1] 0 1 2 3 4 5 6 7 8 9 10
# Privilégier seq_len à : lorsqu'il y a un risque de 0# Fonctionnement identiquen <-51:n
[1] 1 2 3 4 5
seq_len(n)
[1] 1 2 3 4 5
# Problème avec les 0n <-01:n
[1] 1 0
seq_len(n)
integer(0)
# Préférer seq_along à : au cas où la taille de l'objet est 0x <-c() ;length(x)
[1] 0
for (i in1:length(x)) print(i)
[1] 1
[1] 0
for (i inseq_along(x)) print(i)for (i inseq(along=x)) print(i)
# Différences seq, seq_len et seq_along# seq : créé une séquence d'éléments successifs, espacés éventuellement d'un passeq(from =1, to =10, by =2)
[1] 1 3 5 7 9
seq(1, 10, 2)
[1] 1 3 5 7 9
# seq_len : créé une séquence d'éléments de 1 jusqu'au paramètre de la fonction (supposé positif)seq_len(10)
[1] 1 2 3 4 5 6 7 8 9 10
# seq_along : créé une séquence d'éléments de 1 jusqu'au nombre d'éléments du vecteurseq_along(c(7,9,1,0))
[1] 1 2 3 4
# seq se comporte comme seq_along si le vecteur comprend plusieurs éléments, et comme seq_len s'il comprend un seul élément# Plusieurs élémentsvecteur <-c(10, 20, 30)seq_along(vecteur)
[1] 1 2 3
seq_len(vecteur)
[1] 1 2 3 4 5 6 7 8 9 10
seq(vecteur)
[1] 1 2 3
# Un seul élementvecteur <-10seq_along(vecteur)
[1] 1
seq_len(vecteur)
[1] 1 2 3 4 5 6 7 8 9 10
seq(vecteur)
[1] 1 2 3 4 5 6 7 8 9 10
4.6 Fonction pour copier des données R dans le presse-papier et les coller (par exemple dans Excel)
Pour coller des données de R dans Excel, on peut :
faire passer la fonction RCopierColler() proposée ci-dessous sur les données R que l’on souhaite copier dans Excel ;
puis coller le presse-papier directement dans Excel.
La fonction peut être assez pratique.
# Copier des données dans le presse-papierx <- mtcarsCopierColler <-function(x, row.names =FALSE, col.names =TRUE, dec =",", na ="", sep ="\t", quote =FALSE, ...) {write.table(x, "clipboard", sep = sep, row.names = row.names, col.names = col.names, dec = dec, na = na, quote = quote, ...)}# Fonctionne sous système Windows, pas Linux#CopierColler(x)
4.7 Fonctions diverses
browseURL() lance une page Internet.
Outils de débogage :
# Outils de debogageoptions(error = recover)options(error=NULL)
Fonction dput()
# Créer un objet sous forme de code R !data("mtcars")dput(mtcars)
# En tidyverse, la fonction tribble peut être utile pour créer des bases lignes par ligneslibrary(tidyverse)tribble(~x, ~y,"a", 1,"b", 2)
# A tibble: 2 × 2
x y
<chr> <dbl>
1 a 1
2 b 2
# Définir ses propres opérateurs# R reconnait le texte entre %% comme un opérateur binaire# Exemple, simplifier la fonction paste'%+%'<-function(x, y) { paste(x, y, sep ="") }"Groupe_"%+%0:9
4.9 Ajouter des guillemets dans une chaîne de caractères
La fonction shQuote() permet d’ajouter des guillemets dans une chaîne de caractères sous Windows.
paste("valeur =", shQuote("10"))
[1] "valeur = '10'"
5 Importer rapidement un fichier R dans SAS
Le format de données SAS étant propriétaire, il n’est pas possible de créer directement en R des bases SAS d’extension .sas7bdat. Une solution relativement rapide pour importer une base R en SAS est de passer par le format intermédiaire .xpt qui conserve les noms et formats des variables.
5.1 Copie de la base R en format xpt
Il faut d’abord copier la base R en format xpt en utilisant la fonction write_xpt() du package haven. Pour que la manipulation proposée ici fonctionne, il faut bien veiller à ce que la version du xpt soit la version 5.
# On copie la base mtcars en format xpt sur le bureau de l'utilisateurhaven::write_xpt(mtcars, file.path(Sys.getenv("USERPROFILE"), "Desktop", "mtcars.xpt"), version =5)
5.2 Import de la base xpt en SAS
La base R copiée en format xpt peut ensuite être importée en SAS avec le code suivant :
Par défaut, la base est nommée du nom de la base xpt et se trouve dans la work de SAS, mais outlib peut être paramétré avec une autre libname.
Code source
---title: "Trucs et astuces en `R`"lang : frauthor: - name: Nassab ABDALLAH affiliation: Dares/SCS, <nassab.abdallah@travail.gouv.fr> - name: Damien EUZENAT affiliation: Dares/DIP, <damien.euzenat@travail.gouv.fr>format: html: toc: true toc-expand: 1 toc-depth: 2 toc-location: left number-sections: true code-copy: true smooth-scroll: true link-external-icon: true link-external-newwindow: true page-layout: full code-tools: true# format : nativeeditor: sourceembed-resources: truesyntax-definitions: - sas.xml# Summary for listings and search enginesdescription: | Trucs et astuces en `R`.# Date publisheddate: "`r Sys.Date()`"output: rmdformats::robobook: highlight: tango number_sections: truecategories: - R---::: justifyVoici quelques trucs et astuces utiles à connaître sur R, issus en partie des livres [The R Inferno](https://www.burns-stat.com/pages/Tutor/R_inferno.pdf) et [Advanced R](https://adv-r.hadley.nz/), à consulter pour plus de détails.:::# Le fonctionnement du langage `R`## Les types d'objet### Généralités```{r, warning=FALSE, message=FALSE}# En savoir plus sur ses donnéesdata("cars")typeof(cars)class(cars)mode(cars)str(cars)dim(cars)c(is.data.frame(cars), is.list(cars), is.vector(cars), is.array(cars))```La notation L permet d'imposer à `R` de créer un nombre sous format `integer`, moins gourmand en mémoire (pour des raisons d'efficacité).```{r, warning=FALSE, message=FALSE}class(1)class(1L)```### Les listes```{r, warning=FALSE, message=FALSE}# Créer une listeliste <-list()# Pré-allouer une liste de 3 élémentsliste <-vector(mode ="list", 3)liste``````{r, warning=FALSE, message=FALSE}# Ajouter un élément à une listeliste <-list(1, 2)# Il faut passer par cette syntaxeliste <-c(liste, list(3))liste``````{r, warning=FALSE, message=FALSE}# Trier une listeliste <-list("2"=2, "0"=0, "1"=1)listeliste[order(names(liste))]``````{r, warning=FALSE, message=FALSE}# Extraction de listesliste <-list(nombres =1:5, lettres = letters[1:5])liste$nombres``````{r, warning=FALSE, message=FALSE}# On veut faire appel à un élement de la liste à partir d'une variable extérieurevar <-"nombres"``````{r, warning=FALSE, message=FALSE}# Ne marche pas, car nombres est en caractèreliste$var``````{r, warning=FALSE, message=FALSE}# Fonctionneliste[[var]]``````{r, warning=FALSE, message=FALSE}# Sélection dans une listeliste <-list(nombres =1:5, lettres = letters[1:5])liste["nombres"]is.list(liste["nombres"])liste[["nombres"]]is.list(liste[["nombres"]])``````{r, warning=FALSE, message=FALSE}# Suppression des éléments d'une listeliste <-list(nombres =1:5, lettres = letters[1:5])liste[-1]liste["nombres"] <-NULLliste``````{r, warning=FALSE, message=FALSE}# Dernier élément de chaque composante d'une listeliste <-list(1:26, letters)lapply(liste, tail, 1)```## Les affectations### Généralités```{r, warning=FALSE, message=FALSE}# Importance des espacesx<-3# S'agit-il de ?x <-3# Ou de ?x <-3# Il s'agit du premier cas !x``````{r, warning=FALSE, message=FALSE}# Les {} permettent de réaliser une affectation (<-) au sein d'un traitement plus complexe !# Exemple ici : sommer les positions paires multipliées par 2 et les positions impaires multipliées par 3sum({x <-1:6 ; x[1:length(x) %%2==0] <- x[1:length(x) %%2==0] *2 ; x[1:length(x) %%2!=0] <- x[1:length(x) %%2!=0] *3 ; x})``````{r, warning=FALSE, message=FALSE}# Afficher ou non la valeur de l'objet affecté pendant l'affectationx <- pi(x <- pi)```### Le comportement de l'opérateur `c()````{r, warning=FALSE, message=FALSE}# c() est instable : c(x, y) n'est pas forcément du même type que c(y, x)# format doublec(NA, Sys.Date())# format Datec(Sys.Date(), NA)``````{r, warning=FALSE, message=FALSE}# Combiner des dates et date-times avec c() conduit à des résultats potentiellement incorrectsdate <-as.Date("2025-01-01")datetime <-as.POSIXct("2025-01-01 09:00")# Correctc(date, datetime)# Incorrectc(datetime, date)``````{r, warning=FALSE, message=FALSE}# Valeurs manquantes# Si le NA est placé avant, c() supprime tous les attributs# Exemple 1c(as.Date("2025-01-01"), NA)c(NA, as.Date("2025-01-01"))# Exemple 2c(NA, as.POSIXct("2025-01-01 09:00"))c(as.POSIXct("2025-01-01 09:00"), NA)``````{r, warning=FALSE, message=FALSE}# c() convertit de character > complex > double > integer > logicalc(FALSE, 1L, 2.5)c(FALSE, "x")``````{r, warning=FALSE, message=FALSE}# Combiner 2 facteurs donne un integerc(factor("a"), factor("b"))``````{r, warning=FALSE, message=FALSE}# Data frames# c() combines 2 data.frames dans une listedf1 <-data.frame(x =1)df2 <-data.frame(x =2)str(c(df1, df1))```## Les comparaisons```{r, warning=FALSE, message=FALSE, error=TRUE}# Comparaisons multiplesx <-0.5# Correct0< x & x <1# Incorrect0< x <1``````{r, warning=FALSE, message=FALSE}# Opérations mathématiques# Infini1/0# Nan = not a number0/0log(-1)```## Opérateurs de contrôle```{r, warning=FALSE, message=FALSE}# Conditions if / elsex <-1``````{r, warning=FALSE, message=FALSE}# Correctif (identical(x, 1)) {print("x est égal à 1")} else {print("x est différent de 1")}``````{r, warning=FALSE, message=FALSE}# Correctif (identical(x, 1)) {print("x est égal à 1")} else {print("x est différent de 1")}``````{r, warning=FALSE, message=FALSE}# Correctif (identical(x, 1)) print("x est égal à 1") elseprint("x est différent de 1")``````{r, warning=FALSE, message=FALSE}# Correctif (identical(x, 1)) print("x est égal à 1") elseprint("x est différent de 1")``````{r, warning=FALSE, message=FALSE, error=TRUE}# Incorrectif (identical(x, 1)) print("x est égal à 1")elseprint("x est différent de 1")``````{r, warning=FALSE, message=FALSE}# Switch# Fonctions et conditions if / elsecondition <-function(langue ="Français") {if (langue =="Français") {"salut"} elseif (langue =="Anglais") {"hello"} elseif (langue =="Russe") {"привет"} else {stop("salut")}}condition("Anglais")``````{r, warning=FALSE, message=FALSE}# Autre possibilité avec switch, mais à réserver aux variables caractères !condition <-function(langue ="Français") {switch(langue, Français ="salut",Anglais ="hello",Russe ="привет",stop("salut"))}condition("Français")```## Les valeurs manquantes```{r, warning=FALSE, message=FALSE}# Transformer les valeurs manquantes en 0x <-data.frame(X1 =c(1, NA, 2), X2 =c(NA, NA, 3))xx[is.na(x)] <-0x``````{r, warning=FALSE, message=FALSE}# Pour les valeurs manquantes, toujours utiliser is.na et non ==NA==c(3, 1, 3, NA)is.na(c(3, 1, 3, NA))``````{r, warning=FALSE, message=FALSE}# Utiliser %in% et non == pour vérifier une appartenance à plusieurs variablesx1 <-1:6x1 ==c(1, 5)x1 %in%c(1, 5)``````{r, warning=FALSE, message=FALSE}# Sélection de données en cas de valeurs manquantesxna <-c(1, NA, 3, 2, 4, 2)``````{r, warning=FALSE, message=FALSE}# Avec ce code, les NA sont conservésxna[xna ==2]``````{r, warning=FALSE, message=FALSE}# Code sans les NAxna[!is.na(xna) & xna ==2]``````{r, warning=FALSE, message=FALSE}# Code compact sans les NAxna[which(xna ==2)]``````{r, warning=FALSE, message=FALSE}# Incidence des NA dans le calcul de statistiques !# Besoin de l'instruction na.rm = TRUE pour en supprimer l'incidencex <-c(1, 5, 6, NA, 8)mean(x)mean(x, na.rm =TRUE)max(x)max(x, na.rm =TRUE)``````{r, warning=FALSE, message=FALSE}# Une moyenne de NA donne NaN (Not a Number) avec na.rm = TRUE !mean(c(NA, NA, NA), na.rm =TRUE)# Et donne NA avec na.rm = FALSE !mean(c(NA, NA, NA), na.rm =FALSE)```## Sélection d'éléments```{r, warning=FALSE, message=FALSE}# Le 1er élément est numéroté 1 et non 0 comme dans Pythonx <-1:3x[c(0, 4)] <-c(-1, 9)# Marche !!for (i in0:3) print(x[i])``````{r, warning=FALSE, message=FALSE}# Cas où les noms ne sont pas uniquesx <-c(a =1, b =2, a =3)x["a"]x[names(x) %in%"a"]``````{r, warning=FALSE, message=FALSE}# Options drop = FALSEx <-data.frame(X1 =c(1,2), X2 =c(3,4), x3 =c(5,6))is.data.frame(x[, c(1,2)])is.data.frame(x[, c(1)])is.data.frame(x[, c(1), drop =FALSE])``````{r, warning=FALSE, message=FALSE}# Fonction subsetx <-data.frame(x1 =c(1,2), x2 =c(3,4), x3 =c(5,6))subset(x, select = x1)subset(x, select =-x1)``````{r, warning=FALSE, message=FALSE}# Correctsubset(x, x1 ==1)``````{r, warning=FALSE, message=FALSE}# Incorrectsubset(x, x1 =1)``````{r, warning=FALSE, message=FALSE, error=TRUE}# Référence à des noms de colonne non usuelsdf <-data.frame(x =rnorm(5), y =runif(5))names(df) <-1:2# Correctdf$`1`# Incorrectdf$1``````{r, warning=FALSE, message=FALSE}# Utilisation de assign pour assigner une valeur à un objet en le désignant sous forme caractèreassign('objet', 3:5)objetfor (i in1:5) assign(paste('objet', i, sep ='_'), i)objet_5```# Les grandes caractéristiques du langage `R`## Principe de vectorisationUne fonction vectorisée s'applique à tous les éléments du vecteur !!```{r, warning=FALSE, message=FALSE}# Exemple de vecteurvaleurs <-c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)valeurs <-1:10``````{r, warning=FALSE, message=FALSE}# Valeurs au carrévaleurs **2``````{r, warning=FALSE, message=FALSE}# logarithme des valeurslog(valeurs)``````{r, warning=FALSE, message=FALSE}# Maximum des valeursmax(valeurs)``````{r, warning=FALSE, message=FALSE}# Limite des valeursrange(valeurs)``````{r, warning=FALSE, message=FALSE}# Correctmean(valeurs)``````{r, warning=FALSE, message=FALSE}# Correctmean(c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))``````{r, warning=FALSE, message=FALSE}# Inattendumean(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)``````{r, warning=FALSE, message=FALSE}# Attention aux parenthèses !n <-10# Inattendu ! Correspond à (1-1, 2-1, 3-1, ..., 10-1)1:n-1# Correct1:(n-1)``````{r, warning=FALSE, message=FALSE}# Minimum ou maximum élément par élémentx1 <-c(1, 2, 5, 6, 8)x2 <-c(4, 0, 7, 2, 1)# Minimum : 2 possibilitéspmin(x1, x2)mapply(min, x1, x2)# Maximum : 2 possibilitéspmax(x1, x2)mapply(max, x1, x2)``````{r, warning=FALSE, message=FALSE}# Calculer (x - min) / (max - min) pour chaque élément x d'un vecteurx <-c(1,2,3)sapply(x, function(xi, mn, mx) {(xi - mn) / (mx - mn)}, mn =min(x), mx =max(x))```## Principe de coercionDans les comparaisons, les objets R sont successivement convertis en `logical`, `integer`, `numeric`, `complex` et `character`, jusqu'à ce que la comparaison puisse se faire.```{r, warning=FALSE, message=FALSE}# TRUE / FALSE est transformé en integer (1 / 0)TRUE==1TRUE==2FALSE==0``````{r, warning=FALSE, message=FALSE}# TRUE est convertit en characterTRUE=="1"``````{r, warning=FALSE, message=FALSE}# 5 est convertit en character5<'7'``````{r, warning=FALSE, message=FALSE}# 50 est convertit en character50<'7'```## Principe de recyclingEn `R Base`, quand 2 vecteurs ne sont pas de même taille, le plus court vecteur est recyclé pour être de même taille que le plus long vecteur.```{r}# Si la taille du plus long vecteur est un entier multiple de la taile du plus court, R n'affiche pas d'avertissementx <-c(1, 2, 3)y <-c(1, 2, 3, 4, 5, 6)x + y``````{r}# Si la taille du plus long vecteur n'est pas un entier multiple de la taille du plus court, R affiche un avertissementx <-c(1, 2, 3)y <-c(1, 2, 3, 4, 5, 6, 7)x + y``````{r}# Mais certaines fonctions pratiquent le recycling sans avertissementpaste(1:3, 1:2)ifelse(1:3, 1:2, 1:2)``````{r}# Et data.frame() renvoie une erreur#data.frame(1:2, 1:3)```# Le saviez-vous ?## Effets des calculs en virgule flottante```{r, warning=FALSE, message=FALSE}sqrt(2) ^2==21/49*49==1.1== .3/3seq(0, 1, by=.1) == .3unique(c(.3, .4- .1, .5- .2, .6- .3, .7- .4))```## Obtenir de l'informations sur `R````{r, warning=FALSE, message=FALSE, results='hide'}# Informations sur la session de RsessionInfo()Sys.info().Platform# Version de RR.version.stringgetRversion()# Lien vers le bureau de l'utilisateurfile.path(Sys.getenv("USERPROFILE"), "Desktop")# Chemin de l'exécutable R est-il installé ?R.home("bin")# Où sont installés les packages R.libPaths()# Version d'un package installé (ici openxlsx)# packageVersion("openxlsx")```## Le pipe sur RCet opérateur permet d'enchaîner les opérations et d'avoir un code plus lisible.Il existe différents types :- **Le pipe de Rbase :** `|>`- **Le pipe du tidyverse :** `%>%`Les deux pipes fonctionnent de la même manière mais diffèrent sur les points suivants :+-----------------------------------------------+---------------------------+-----------------------------------------------------------------------+| Thème |`|>`|`%>%`|+===============================================+===========================+=======================================================================+| Placeholder (pour indiquer où placer l'objet) |`_`|`.`|||||||`x |> f(y, a = _)`|`x %>% f(y, a = .)`|+-----------------------------------------------+---------------------------+-----------------------------------------------------------------------+| Package | Aucun : directement sur R | Magrittr (pipe disponible lorsqu'on effectue `library(tidyverse)`) \||+-----------------------------------------------+---------------------------+-----------------------------------------------------------------------+| Fonction | Impossible | Possible |+-----------------------------------------------+---------------------------+-----------------------------------------------------------------------+| Temps de calcul | Rapide | Plus lent |+-----------------------------------------------+---------------------------+-----------------------------------------------------------------------+| Opérateurs |`|>`|`%>%``%<>%``%$%``%!>%``%T>%`|+-----------------------------------------------+---------------------------+-----------------------------------------------------------------------+*Source* :- <https://larmarange.github.io/guide-R/manipulation/pipe.html#le-pipe-natif-de-r>## Conseils diversLe format en résultat de `sapply` est imprévisible :```{r, warning=FALSE, message=FALSE}# integersapply(1L, function(x) c(x, x))# listsapply(integer(), function(x) c(x, x))```Le résultat de `ifelse()` dépend du format de la condition :```{r, warning=FALSE, message=FALSE}# logicalifelse(NA, 1L, 1L)# integerifelse(FALSE, 1L, 1L)```La fonction `if` utilisée sans `else` renvoie `NULL` si la condition est `FALSE`. Ceci permet d'écrire de façon élégante des conditions simples. Par exemple, prendre en compte un s final à un nom seulement si la valeur est strictement supérieure à 1 :```{r, warning=FALSE, message=FALSE}NombreDeLignes <-function(baseDeDonnees) { ligne <-nrow(baseDeDonnees)paste0(ligne, " ligne", if (ligne >1) "s")}NombreDeLignes(mtcars)NombreDeLignes(mtcars[1,])```Pré-allouer un vecteur de dimension 3 :```{r, warning=FALSE, message=FALSE}x <-rep(NA, 3)```## List-comprehensions en `R`Equivalent des list-comprehensions de `Python` en `R` !```{r, warning=FALSE, message=FALSE}# Equivalent des list-comprehensions de Python en R# Somme des entiers de 1 à 1 000 multiples de 3 ou 5, en une ligne !# 4 manières de fairesum({l <-1:1000 ; l[l %%3==0| l %%5==0]})sum({l <-1:1000 ; l[seq_along(l) %%3==0|seq_along(l) %%5==0]})sum(l<-(1:1000)[l %%3==0| l %%5==0])sum((1:1000)[(1:1000%%3) ==0| (1:1000%%5) ==0])```# Fonctions utiles## Ramasse-miettes (Garbage Collector)Si la mémoire vive de l'ordinateur est saturée, on peut essayer de la "purger" en utilisant la fonction `gc()` de `R`.```{r, warning=FALSE, message=FALSE}gc()```## La fonction `subset()`La fonction `subset()` présente deux intérêts par rapport à la sélection avec `[` :- les lignes où la condition évaluée est `NA` sont retirées :```{r, warning=FALSE, message=FALSE}exemple_subset <-data.frame(x =c(1, 2, NA), y =c("a", "b", "c"))# Avec []exemple_subset[exemple_subset$x ==1, ]# Avec subset()subset(exemple_subset, x ==1)```- l'option par défaut est `drop = FALSE`, ce qui garantit que la base de résultat est un dataframe :```{r, warning=FALSE, message=FALSE}library(tidyverse)exemple_subset <-data.frame(x =c(1, 2, NA), y =c("a", "b", "c"))# Avec []exemple_subset[exemple_subset$x ==1, "x"] %>%is.data.frame()# Avec subset()subset(exemple_subset, x ==1, x) %>%is.data.frame()```## Les fonctions `try()` et `tryCatch()`La fonction `try()` permet de poursuivre le programme malgré la survenue d'une erreur. Dans l'exemple suivant, le programme affiche bien "Suite du programme" malgré l'erreur au code précédent.```{r, warning=FALSE, message=FALSE}try(log("x")) ; print("Suite du programme")```La fonction `tryCatch()` est plus élaborée, et permet de programmer une valeur par défaut en cas d'erreur.```{r, warning=FALSE, message=FALSE}FonctionLog <-function(x) {tryCatch(error =function(cnd) NA,log(x) )}```La fonction renvoie un `NA` si la fonction `log()` ne peut pas être appliquée, comme c'est le cas sur l'exemple pour la valeur "a".```{r, warning=FALSE, message=FALSE}FonctionLog(1)FonctionLog("x")```## Les fonctions `sort()`, `order()` et `rank()``sort()` trie un vecteur par ordre croissant. `rank()` donne le rang de chaque élément du vecteur, le plus petit élément se voyant attribué le rang 1. `order()` renvoie l'indice du vecteur trié par ordre croissant.```{r, warning=FALSE, message=FALSE}vecteur <-c(5,3,1,2,4)sort(vecteur)order(vecteur)rank(vecteur)```Une autre solution que `sort()` pour trier un vecteur est :```{r, warning=FALSE, message=FALSE}vecteur <-c(5,3,1,2,4)vecteur[order(vecteur)]```À noter aussi que `sort()` permet aussi d'exécuter simultanément les fonctions `sort()` et `order()`. Ainsi :```{r, warning=FALSE, message=FALSE}vecteur <-c(5,3,1,2,4)sort(vecteur, index.return =TRUE)# Fonction sort()sort(vecteur, index.return =TRUE)$xsort(vecteur)# Fonction order()sort(vecteur, index.return =TRUE)$ixorder(vecteur)```## Les fonctions `:`, `seq()`, `seq_len()` et `seq_along()````{r, warning=FALSE, message=FALSE}# Ne pas confondre !seq(0:10)0:10seq(0, 10)``````{r, warning=FALSE, message=FALSE}# Privilégier seq_len à : lorsqu'il y a un risque de 0# Fonctionnement identiquen <-51:nseq_len(n)# Problème avec les 0n <-01:nseq_len(n)``````{r, warning=FALSE, message=FALSE}# Préférer seq_along à : au cas où la taille de l'objet est 0x <-c() ;length(x)for (i in1:length(x)) print(i)for (i inseq_along(x)) print(i)for (i inseq(along=x)) print(i)``````{r, warning=FALSE, message=FALSE}# Différences seq, seq_len et seq_along# seq : créé une séquence d'éléments successifs, espacés éventuellement d'un passeq(from =1, to =10, by =2)seq(1, 10, 2)# seq_len : créé une séquence d'éléments de 1 jusqu'au paramètre de la fonction (supposé positif)seq_len(10)# seq_along : créé une séquence d'éléments de 1 jusqu'au nombre d'éléments du vecteurseq_along(c(7,9,1,0))# seq se comporte comme seq_along si le vecteur comprend plusieurs éléments, et comme seq_len s'il comprend un seul élément# Plusieurs élémentsvecteur <-c(10, 20, 30)seq_along(vecteur)seq_len(vecteur)seq(vecteur)# Un seul élementvecteur <-10seq_along(vecteur)seq_len(vecteur)seq(vecteur)```## Fonction pour copier des données R dans le presse-papier et les coller (par exemple dans Excel)Pour coller des données de R dans Excel, on peut :- faire passer la fonction `R``CopierColler()` proposée ci-dessous sur les données `R` que l'on souhaite copier dans Excel ;- puis coller le presse-papier directement dans Excel.La fonction peut être assez pratique.```{r, warning=FALSE, message=FALSE}# Copier des données dans le presse-papierx <- mtcarsCopierColler <-function(x, row.names =FALSE, col.names =TRUE, dec =",", na ="", sep ="\t", quote =FALSE, ...) {write.table(x, "clipboard", sep = sep, row.names = row.names, col.names = col.names, dec = dec, na = na, quote = quote, ...)}# Fonctionne sous système Windows, pas Linux#CopierColler(x)```## Fonctions diverses`browseURL()` lance une page Internet.Outils de débogage :```{r, warning=FALSE, message=FALSE}# Outils de debogageoptions(error = recover)options(error=NULL)```Fonction `dput()````{r, warning=FALSE, message=FALSE}# Créer un objet sous forme de code R !data("mtcars")dput(mtcars)```Fonction `tribble()````{r, warning=FALSE, message=FALSE}# En tidyverse, la fonction tribble peut être utile pour créer des bases lignes par ligneslibrary(tidyverse)tribble(~x, ~y,"a", 1,"b", 2)``````{r, warning=FALSE, message=FALSE}# Définir ses propres opérateurs# R reconnait le texte entre %% comme un opérateur binaire# Exemple, simplifier la fonction paste'%+%'<-function(x, y) { paste(x, y, sep ="") }"Groupe_"%+%0:9``````{r, warning=FALSE, message=FALSE}# Récupérer les éléments à la diagonale d'un dataframediag(as.matrix(mtcars))``````{r, warning=FALSE, message=FALSE}# S'assurer qu'un objet R existe déjàexists("mtcars")``````{r, warning=FALSE, message=FALSE}# Penser au printfor (i in1:5) ifor (i in1:5) print(i)``````{r, warning=FALSE, message=FALSE}# Différences print et catcat("Salut !\nComment vas-tu ?")print("Salut !\nComment vas-tu ?")```## Quelques fonctions mathématiques`integrate()` calcule l'aire sous la courbe $f()$.```{r, warning=FALSE, message=FALSE}integrate(sin, 0, pi /2)````uniroot()` trouve la valeur de $x$ telle que $f(x) = 0$.```{r, warning=FALSE, message=FALSE}uniroot(function(x) x **3, c(-1, 1))````optimise()` trouve le maximum ou le minimum d'une fonction sur un intervalle donné.```{r, warning=FALSE, message=FALSE}optimise(function(x) -x **2, c(-1, 1), maximum =TRUE)```## Ajouter des guillemets dans une chaîne de caractèresLa fonction `shQuote()` permet d'ajouter des guillemets dans une chaîne de caractères sous Windows.```{r, warning=FALSE, message=FALSE}paste("valeur =", shQuote("10"))```# Importer rapidement un fichier `R` dans `SAS`Le format de données `SAS` étant propriétaire, il n'est pas possible de créer directement en `R` des bases `SAS` d'extension `.sas7bdat`. Une solution relativement rapide pour importer une base `R` en `SAS` est de passer par le format intermédiaire `.xpt` qui conserve les noms et formats des variables.## Copie de la base `R` en format `xpt`Il faut d'abord copier la base `R` en format `xpt` en utilisant la fonction `write_xpt()` du package `haven`. Pour que la manipulation proposée ici fonctionne, il faut bien veiller à ce que la version du `xpt` soit la version 5.```{r, warning=FALSE, message=FALSE}#| eval: false# On copie la base mtcars en format xpt sur le bureau de l'utilisateurhaven::write_xpt(mtcars, file.path(Sys.getenv("USERPROFILE"), "Desktop", "mtcars.xpt"), version =5)```## Import de la base `xpt` en `SAS`La base `R` copiée en format `xpt` peut ensuite être importée en `SAS` avec le code suivant :``` saslibname xptfile xport "C:\Users\&sysuserid.\Desktop\mtcars.xpt";proc copy inlib = xptfile outlib = work;run;```Par défaut, la base est nommée du nom de la base `xpt` et se trouve dans la `work` de `SAS`, mais `outlib` peut être paramétré avec une autre libname.